//
// Copyright (C) Ian Horswill 2004, 2005, 2006; See the file COPYING for licensing information.
//
using System;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.Security.Permissions;


namespace Meta {
	[Serializable]
	public class Symbol : ISerializable {

#if XMLSerializeKluge
		public Symbol() {
			name = "<<bogus>>";
		}
#endif

		protected Symbol(String nameArg, String plainNameArg)  {
			name=nameArg;
			plainName=plainNameArg;
		}
		[SoapAttribute]
		public String name;
		[NonSerialized]
		public String plainName;
		public override String ToString() {
			return name;
		}

		[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter =true)]
		void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
			info.SetType(typeof(SymbolRef));
			info.AddValue("name", name);
		}

		private static System.Collections.Hashtable symbolTable = new System.Collections.Hashtable();
		public static Symbol sAssignmentArrow = Symbol.Intern("<-");
		public static Symbol sLambdaArrow = Symbol.Intern("->");
		public static Symbol sListOf = Symbol.Intern("list-of");
		public static Symbol sAnd = Symbol.Intern("and");
		public static Symbol sBegin = Symbol.Intern("begin");
		public static Symbol sBody = Symbol.Intern("body");
		public static Symbol sColon = Symbol.Intern(":");
		public static Symbol sDefine = Symbol.Intern("define");
		public static Symbol sIf = Symbol.Intern("if");
		public static Symbol sMember = Symbol.Intern("member");
		public static Symbol sNot = Symbol.Intern("not");
		public static Symbol sOr = Symbol.Intern("or");
		public static Symbol sQuote = Symbol.Intern("quote");
		public static Symbol sUnquote = Symbol.Intern("unquote");
		public static Symbol sUnquoteSplicing = Symbol.Intern("unquote-splicing");
		public static Symbol sQuasiquote = Symbol.Intern("quasiquote");
		public static Symbol sWhile = Symbol.Intern("while");
		public static Symbol sWith = Symbol.Intern("with");
		public static Symbol sWithStar = Symbol.Intern("with*");
		public static Symbol sWith2 = Symbol.Intern("with:");
		public static Symbol sWithStar2 = Symbol.Intern("with*:");
		public static Symbol sList = Symbol.Intern("list");
		public static Symbol sUnnamed = Symbol.Intern("<unnamed>");
		public static Symbol sEllipsis = Symbol.Intern("...");
		public static Symbol sEqual = Symbol.Intern("=");
		public static Symbol sSetter = Symbol.Intern("setter");
		public static Symbol sApply = Symbol.Intern("apply");
		public static Symbol sSelf = Symbol.Intern("self");
		public static Symbol sAll = Symbol.Intern("all");
		public static void AddSynonym(String oldName, String newName) {
			Symbol.symbolTable[newName] = Symbol.Intern(oldName);
		}
		public static void Rename(String oldName, String newName) {
			Symbol sym = Symbol.Intern(oldName);
			Symbol.symbolTable[newName] = sym;
			sym.name = newName;
		}
		public static Symbol MaybeIntern(String name) {
			return ((Symbol)((Symbol.symbolTable[name])));
		}
		public virtual Keyword KeywordForm {

			get {
				return ((Keyword)(Symbol.Intern(name+":")));
			}
		}
		public virtual Symbol SymbolForm {

			get {
				return this;
			}
		}
		public static Symbol Intern(String name) {
			System.Threading.Monitor.Enter(typeof(Symbol));
			Symbol probe = ((Symbol)((Symbol.symbolTable[name])));
			Symbol result = null;
			if (probe==null) {
				Symbol sym = (((bool)(name.EndsWith(":")))?new Keyword(name, name):new Symbol(name, name));
				Symbol.symbolTable[name] = sym;
				result = sym;
			} else
				result = probe;
			System.Threading.Monitor.Exit(typeof(Symbol));
			return result;
		}
	}

	[Serializable]
	public class SymbolRef : IObjectReference {
		[SoapAttribute]
		string name;
		object IObjectReference.GetRealObject(StreamingContext context) {
			name = name;   // need this to defeat compiler warning that name is never assigned to.
			return Symbol.Intern(name);
		}
	}

	// It's a gross kluge that this is included here rather than symbol.cs, but the macro processor can't hack
	// non-trivial constructors.
	[Serializable]
	public class Keyword : Symbol, ISerializable {

#if XMLSerializeKluge
		public Keyword() {
			name = "<<bogus>>";
		}
#endif

		internal Keyword(string pname, string plainname) : base(pname, plainname) {
		}

		[NonSerialized]
		Symbol symbolForm;

		public string NameWithoutColon {
			get {
				return name.Substring(0, name.Length-1);
			}
		}

		public override Keyword KeywordForm {
			get {
				return this;
			}
		}

		public override Symbol SymbolForm {
			get {
				if (symbolForm==null)
					symbolForm = Intern(NameWithoutColon);
				return symbolForm;
			}
		}

	}
}